using System;
using System.Collections.Generic;
using System.Dynamic;
using System.Linq;
using System.ServiceModel;
using AutoMapper;
using Core;
using IglooCoder.Commons.WcfNhibernate;
using Infrastucture;
using Omu.ValueInjecter;
using WcfService1.DTO;

namespace WcfService1
{
    // NOTE: You can use the "Rename" command on the "Refactor" DeliveryOrderElse to change the class name "DeliveryOrderElseServices" in code, svc and config file together.
    [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
    [NHibernateContext]
    public class DeliveryOrderElseServices : IDeliveryOrderElseServices
    {
        private readonly DeliveryOrderElseRepository DeliveryOrderElseRepository;
        private readonly InventoryWarehouseRepository _iwRepository;
        private readonly MutasiStokRepository _mutasiStokRepository;
        private readonly WcfSessionStorage _session;
        private InventoryRepository InventoryRep;
        private SalesOrderRepository _SORepository;
        private readonly InventoryRepository _InventoryRepository;
        private readonly JurnalRepository _jurnalRepository;
        private readonly HppRepository _hppRepository;

        public DeliveryOrderElseServices()
        {
            _session = new WcfSessionStorage();
            DeliveryOrderElseRepository = new DeliveryOrderElseRepository(_session);
            InventoryRep = new InventoryRepository(_session);
            _mutasiStokRepository = new MutasiStokRepository(_session);
            _iwRepository = new InventoryWarehouseRepository(_session);
            _SORepository = new SalesOrderRepository(_session);
            _InventoryRepository = new InventoryRepository(_session);
            _jurnalRepository  = new JurnalRepository(_session);
            _hppRepository = new HppRepository(_session);
        }

        #region IDeliveryOrderElseServices Members

        public List<DeliveryOrderElseDTO> GetList(int page, out long recordCount, string sortProperty = null,
                                                  string sortType = "ASC")
        {
            var DeliveryOrderElses = new List<DeliveryOrderElse>();
            var Results = new List<DeliveryOrderElseDTO>();

            if (string.IsNullOrEmpty(sortProperty))
            {
                DeliveryOrderElses = DeliveryOrderElseRepository.GetDataPaged(page, 30).ToList();
            }
            else
            {
                DeliveryOrderElses = DeliveryOrderElseRepository.GetDataPaged(page, 30, sortProperty, sortType).ToList();
            }

            recordCount = DeliveryOrderElseRepository.RecordCount;

            //DeliveryOrderElses.ForEach(x =>
            //{

            //    DeliveryOrderElseDTO DeliveryOrderElseDto = new DeliveryOrderElseDTO();
            //    AutoMapper.Mapper.Map(x, DeliveryOrderElseDto);
            //    Results.Add(DeliveryOrderElseDto);
            //}
            //    );


            Results = (from d in DeliveryOrderElses
                       select new DeliveryOrderElseDTO
                                  {
                                      DONo = d.DONo,
                                      DODate = d.DODate,
                                      DeliveryType = d.DeliveryType.ConvertToDTO<DeliveryType, DeliveryTypeDTO>(),
                                      Description = d.Description,
                                      DeliveryAddress = d.DeliveryAddress,
                                      CustomerName = d.CustomerName,
                                      Address = d.Address,
                                      Telp = d.Telp
                                  }).ToList();

            return Results;
        }

        public bool Save(DeliveryOrderElseDTO DeliveryOrderElseDTO, out string err)
        {
            err = string.Empty;
            bool res;
            bool IsNew = false;
            try
            {
                DeliveryOrderElse DeliveryOrderElse =
                    DeliveryOrderElseRepository.GetDataOne(x => x.DONo == DeliveryOrderElseDTO.DONo);

                if (DeliveryOrderElse == null)
                {
                    DeliveryOrderElse = new DeliveryOrderElse();
                    IsNew = true;
                }

                Mapper.Map(DeliveryOrderElseDTO, DeliveryOrderElse);

                DeliveryOrderElseRepository
                    .ExecuteTransactionNative(() =>
                                                  {
                                                      if (!IsNew)
                                                          _mutasiStokRepository.DeleteMutasiStok(DeliveryOrderElse.DONo);

                                                      foreach (
                                                          DeliveryOrderElseDetail DeliveryOrderElseDetail in
                                                              DeliveryOrderElse.DeliveryOrderDetails)
                                                      {
                                                          //Mutasi Keluar
                                                          var mutasiStok = new MutasiStok();
                                                          mutasiStok.SerialNumber =
                                                              DeliveryOrderElseDetail.Inventory.SerialNumber;
                                                          mutasiStok.ReferenceNumber = DeliveryOrderElse.DONo;
                                                          mutasiStok.TglMutasi = DeliveryOrderElse.DODate.ToDateTimeSell();
                                                          mutasiStok.Type = DeliveryOrderElse.GetType().Name;
                                                          mutasiStok.QtyKeluar = DeliveryOrderElseDetail.QtyUnit;
                                                          MutasiStok mutasiLast =
                                                              _mutasiStokRepository.FindLastMutasi(
                                                                  mutasiStok.SerialNumber,
                                                                  DeliveryOrderElseDetail.Warehouse.KodeWarehouse);
                                                          mutasiStok.QtySisa = mutasiLast.QtySisa - mutasiStok.QtyKeluar;
                                                          mutasiStok.SheetKeluar = DeliveryOrderElseDetail.Tinggi;
                                                          mutasiStok.SheetSisa = mutasiLast.SheetSisa -
                                                                                 mutasiStok.SheetKeluar;
                                                          mutasiStok.KodeWarehouse =
                                                              DeliveryOrderElseDetail.Warehouse.KodeWarehouse;
                                                          if (mutasiStok.QtySisa < 0)
                                                              throw new Exception(mutasiStok.SerialNumber + " Stok Tidak Mencukupi!");
                                                          //if (DeliveryOrderElseDetail.Inventory.Item.IsRounded)
                                                              if (mutasiStok.QtySisa < Convert.ToDecimal(0.0999))
                                                                  mutasiStok.QtySisa = 0;
                                                          _mutasiStokRepository.SaveOrUpdate(mutasiStok);
                                                      }
                                                      DeliveryOrderElseRepository.SaveOrUpdate(DeliveryOrderElse);
                                                  });

                res = true;
            }
            catch (Exception ex)
            {
                err = ex.Message;
                res = false;
                throw ex;
            }

            return res;
        }


        public bool Delete(DeliveryOrderElseDTO DeliveryOrderElseDto)
        {
            bool res;
            try
            {
                DeliveryOrderElse DeliveryOrderElse =
                    DeliveryOrderElseRepository.GetDataOne(x => x.DONo == DeliveryOrderElseDto.DONo);
                DeliveryOrderElseRepository.ExecuteTransactionNative(
                    () =>
                        {
                            _mutasiStokRepository.DeleteMutasiStok(DeliveryOrderElse.DONo);
                            DeliveryOrderElse.Status = 2;
                            DeliveryOrderElseRepository.SaveOrUpdate(DeliveryOrderElse);
                        }
                    );

                res = true;
            }
            catch (Exception)
            {
                res = false;
            }

            return res;
        }


        public List<DeliveryOrderElseDTO> GetListByCriteria(Dictionary<String, Object> criteria, string expression,
                                                            int page, out long recordCount)
        {
            var DeliveryOrderElses = new List<DeliveryOrderElse>();
            var Results = new List<DeliveryOrderElseDTO>();
            DeliveryOrderElses = DeliveryOrderElseRepository.GetDataPaged(criteria, expression, page, 30).ToList();
            recordCount = DeliveryOrderElseRepository.RecordCount;
            DeliveryOrderElses.ForEach(x =>
                                           {
                                               var DeliveryOrderElseDto = new DeliveryOrderElseDTO();
                                               Mapper.Map(x, DeliveryOrderElseDto);
                                               Results.Add(DeliveryOrderElseDto);
                                           }
                );

            return Results;
        }


        public List<DeliveryOrderElseDTO> GetAllDeliveryOrderElse()
        {
            List<DeliveryOrderElse> DeliveryOrderElses = DeliveryOrderElseRepository.FetchAll().ToList();
            IEnumerable<DeliveryOrderElseDTO> Results = from d in DeliveryOrderElses
                                                        select new DeliveryOrderElseDTO {DONo = d.DONo};

            return Results.ToList();
        }


        public DeliveryOrderElseDTO GetDeliveryOrderElse(String kodeDeliveryOrderElse)
        {
            DeliveryOrderElse DeliveryOrderElse =
                DeliveryOrderElseRepository.GetDataOne(x => x.DONo == kodeDeliveryOrderElse);
            var DeliveryOrderElseDto = new DeliveryOrderElseDTO();
            Mapper.Map(DeliveryOrderElse, DeliveryOrderElseDto);
            return DeliveryOrderElseDto;
        }

        public List<DeliveryOrderElseDTO> GetDeliveryOrderElseList(string kodeDeliveryOrderElse)
        {
            List<DeliveryOrderElse> DeliveryOrderElses =
                DeliveryOrderElseRepository.GetDataList(x => x.DONo.Contains(kodeDeliveryOrderElse)).ToList();
            var Results = new List<DeliveryOrderElseDTO>();
            DeliveryOrderElses.ForEach(x =>
                                           {
                                               var DeliveryOrderElseDto = new DeliveryOrderElseDTO();
                                               Mapper.Map(x, DeliveryOrderElseDto);
                                               Results.Add(DeliveryOrderElseDto);
                                           }
                );

            return Results;
        }


        public string GetLastDONo()
        {
            string res = DeliveryOrderElseRepository.GetMaxNumber();
            var appParamServices = new AppParamServices();
            AppParamDTO param = appParamServices.GetAppParamList("KodeDO").FirstOrDefault();
            return string.IsNullOrEmpty(res) ? param.AppParamValue : res;
        }


        public bool DeleteDetail(DeliveryOrderElseDetailDTO DeliveryOrderElseDetailDto)
        {
            bool res;
            try
            {
                var DODetail =
                    DeliveryOrderElseRepository.Session.Get<DeliveryOrderElseDetail>(
                        DeliveryOrderElseDetailDto.DeliveryOrderDetailId);
                DeliveryOrderElseRepository.ExecuteTransactionNative(
                    () =>
                        {
                            _mutasiStokRepository.DeleteMutasiStok(DeliveryOrderElseDetailDto.DoNo,
                                                                   DeliveryOrderElseDetailDto.Inventory.SerialNumber);
                            DeliveryOrderElseRepository.DeleteDetail(DODetail,
                                                                     DeliveryOrderElseDetailDto.DeliveryOrderDetailId);
                        });

                res = true;
            }
            catch (Exception)
            {
                res = false;
            }

            return res;
        }

        public bool SendEmail(DeliveryOrderElseDTO DeliveryOrderElseDto, String DestinationFolder)
        {
            var mailServices = new MailServices();
            DeliveryOrderElse DeliveryOrderElse =
                DeliveryOrderElseRepository.GetDataOne(x => x.DONo == DeliveryOrderElseDto.DONo);
            DeliveryOrderElseDto = Mapper.Map(DeliveryOrderElse, DeliveryOrderElseDto);
            return mailServices.SendEmail(DeliveryOrderElseDto,DestinationFolder);
        }

        public IEnumerable<DeliveryOrderElseDTO> GetListByPeriode(DateTime tglstart, DateTime tglend)
        {
            var  doElses = new List<DeliveryOrderElse>();
            doElses = DeliveryOrderElseRepository.GetDataList(x => x.DODate >= tglstart && x.DODate <= tglend).ToList();
            var results = new List<DeliveryOrderElseDTO>();

            foreach (var doElse in doElses)
            {
                var doElseDTO = new DeliveryOrderElseDTO();
                doElseDTO.InjectFrom(doElse);
                results.Add(doElseDTO);
            }

            return results;
        }


        public void CreateJurnal(DeliveryOrderElse deliveryOrderElse)
        {
            //Piutang
            Jurnal jurnal = new Jurnal();
            jurnal.NoVoucher = deliveryOrderElse.DONo;
            jurnal.TglJurnal = deliveryOrderElse.DODate;
            jurnal.Description = deliveryOrderElse.Description;
            jurnal.ReffNumber = deliveryOrderElse.DONo;
            jurnal.TipeJurnal = typeof(DeliveryOrderElse).Name;
            
            foreach (var detail in deliveryOrderElse.DeliveryOrderDetails)
            {
                    //Biaya
                    var inventory = _InventoryRepository.GetDataOne(x => x.SerialNumber == detail.Inventory.SerialNumber);
                    var hpp = _hppRepository.FindLastHpp(inventory.SerialNumber, deliveryOrderElse.DODate);
                    if (hpp.QtyAkhir == 0) throw new Exception("hpp " + inventory.SerialNumber + " tidak ada!");

                    jurnal.JurnalDetails.Add(new JurnalDetail() { AccountNumber = inventory.Item.CoaExpense, Debit = detail.QtyUnit * hpp.HppAkhir, Jurnal = jurnal, Description = inventory.Item.ItemId + ":" + inventory.Item.CoaExpense });
                    //Inventory Kredit
                    jurnal.JurnalDetails.Add(new JurnalDetail() { AccountNumber = inventory.Item.CoaInventory, Kredit = detail.QtyUnit * hpp.HppAkhir, Jurnal = jurnal, Description = inventory.Item.ItemId + ":" + inventory.Item.CoaInventory });
            }


            List<JurnalDetail> results = new List<JurnalDetail>();
            foreach (var gjd in jurnal.JurnalDetails.GroupBy(x=>x.Description))
            {
                results.Add(new JurnalDetail()
                                {
                                    AccountNumber = jurnal.JurnalDetails.FirstOrDefault(x =>x.Description == gjd.Key).AccountNumber,
                                    Debit = jurnal.JurnalDetails.Where(x => x.Description == gjd.Key).Sum(x => x.Debit),
                                    Kredit = jurnal.JurnalDetails.Where(x => x.Description == gjd.Key).Sum(x => x.Kredit),
                                    Description = jurnal.JurnalDetails.FirstOrDefault(x => x.Description == gjd.Key).Description,
                                    Jurnal = jurnal
                                });
            }

            jurnal.JurnalDetails = results;
            _jurnalRepository.SaveOrUpdate(jurnal);
            var hppServices = new HppServices();
            hppServices.CreateHpp(deliveryOrderElse);

        }


        public void Posting(IEnumerable<DeliveryOrderElseDTO> deliveryOrderElses)
        {
            DeliveryOrderElseRepository.ExecuteTransactionNative(() =>
            {
                foreach (var deliveryOrderElse in deliveryOrderElses)
                {
                    var doElse = DeliveryOrderElseRepository.GetDataOne(x => x.DONo == deliveryOrderElse.DONo);
                    DeliveryOrderElseRepository.UpdateStatus(deliveryOrderElse.DONo, 3);
                    CreateJurnal(doElse);
                }
            });

        }


        public void UnPosting(IEnumerable<DeliveryOrderElseDTO> deliveryOrderElseDtos)
        {
            DeliveryOrderElseRepository.ExecuteTransactionNative(() =>
            {
                foreach (var deliveryOrderElseDto in deliveryOrderElseDtos)
                {
                    var deliveryOrderElse = DeliveryOrderElseRepository.GetDataOne(x => x.DONo == deliveryOrderElseDto.DONo);
                    DeliveryOrderElseRepository.UpdateStatus(deliveryOrderElse.DONo, 0);
                    var jurnal = _jurnalRepository.GetDataOne(x => x.NoVoucher == deliveryOrderElse.DONo);
                    _jurnalRepository.Delete(jurnal);
                    _hppRepository.DeleteHpp(deliveryOrderElse.DONo);
                }
            });

        }

        #endregion
    }
}